home *** CD-ROM | disk | FTP | other *** search
/ Introduction to 3D Game …ogramming with DirectX 12 / Introduction-to-3D-Game-Programming-with-DirectX-12.ISO / Code.Textures / Chapter 17 Picking / Picking / PickingApp.cpp < prev   
Encoding:
C/C++ Source or Header  |  2016-03-02  |  33.4 KB  |  964 lines

  1. //***************************************************************************************
  2. // PickingApp.cpp by Frank Luna (C) 2015 All Rights Reserved.
  3. //***************************************************************************************
  4.  
  5. #include "../../Common/d3dApp.h"
  6. #include "../../Common/MathHelper.h"
  7. #include "../../Common/UploadBuffer.h"
  8. #include "../../Common/GeometryGenerator.h"
  9. #include "../../Common/Camera.h"
  10. #include "FrameResource.h"
  11.  
  12. using Microsoft::WRL::ComPtr;
  13. using namespace DirectX;
  14. using namespace DirectX::PackedVector;
  15.  
  16. #pragma comment(lib, "d3dcompiler.lib")
  17. #pragma comment(lib, "D3D12.lib")
  18.  
  19. const int gNumFrameResources = 3;
  20.  
  21. // Lightweight structure stores parameters to draw a shape.  This will
  22. // vary from app-to-app.
  23. struct RenderItem
  24. {
  25.     RenderItem() = default;
  26.     RenderItem(const RenderItem& rhs) = delete;
  27.  
  28.     bool Visible = true;
  29.  
  30.     BoundingBox Bounds;
  31.  
  32.     // World matrix of the shape that describes the object's local space
  33.     // relative to the world space, which defines the position, orientation,
  34.     // and scale of the object in the world.
  35.     XMFLOAT4X4 World = MathHelper::Identity4x4();
  36.  
  37.     XMFLOAT4X4 TexTransform = MathHelper::Identity4x4();
  38.  
  39.     // Dirty flag indicating the object data has changed and we need to update the constant buffer.
  40.     // Because we have an object cbuffer for each FrameResource, we have to apply the
  41.     // update to each FrameResource.  Thus, when we modify obect data we should set 
  42.     // NumFramesDirty = gNumFrameResources so that each frame resource gets the update.
  43.     int NumFramesDirty = gNumFrameResources;
  44.  
  45.     // Index into GPU constant buffer corresponding to the ObjectCB for this render item.
  46.     UINT ObjCBIndex = -1;
  47.  
  48.     Material* Mat = nullptr;
  49.     MeshGeometry* Geo = nullptr;
  50.  
  51.     // Primitive topology.
  52.     D3D12_PRIMITIVE_TOPOLOGY PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  53.  
  54.     // DrawIndexedInstanced parameters.
  55.     UINT IndexCount = 0;
  56.     UINT StartIndexLocation = 0;
  57.     int BaseVertexLocation = 0;
  58. };
  59.  
  60. enum class RenderLayer : int
  61. {
  62.     Opaque = 0,
  63.     Highlight,
  64.     Count
  65. };
  66.  
  67. class PickingApp : public D3DApp
  68. {
  69. public:
  70.     PickingApp(HINSTANCE hInstance);
  71.     PickingApp(const PickingApp& rhs) = delete;
  72.     PickingApp& operator=(const PickingApp& rhs) = delete;
  73.     ~PickingApp();
  74.  
  75.     virtual bool Initialize()override;
  76.  
  77. private:
  78.     virtual void OnResize()override;
  79.     virtual void Update(const GameTimer& gt)override;
  80.     virtual void Draw(const GameTimer& gt)override;
  81.  
  82.     virtual void OnMouseDown(WPARAM btnState, int x, int y)override;
  83.     virtual void OnMouseUp(WPARAM btnState, int x, int y)override;
  84.     virtual void OnMouseMove(WPARAM btnState, int x, int y)override;
  85.  
  86.     void OnKeyboardInput(const GameTimer& gt);
  87.     void AnimateMaterials(const GameTimer& gt);
  88.     void UpdateObjectCBs(const GameTimer& gt);
  89.     void UpdateMaterialBuffer(const GameTimer& gt);
  90.     void UpdateMainPassCB(const GameTimer& gt);
  91.  
  92.     void LoadTextures();
  93.     void BuildRootSignature();
  94.     void BuildDescriptorHeaps();
  95.     void BuildShadersAndInputLayout();
  96.     void BuildCarGeometry();
  97.     void BuildPSOs();
  98.     void BuildFrameResources();
  99.     void BuildMaterials();
  100.     void BuildRenderItems();
  101.     void DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems);
  102.     void Pick(int sx, int sy);
  103.  
  104.     std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> GetStaticSamplers();
  105.  
  106. private:
  107.  
  108.     std::vector<std::unique_ptr<FrameResource>> mFrameResources;
  109.     FrameResource* mCurrFrameResource = nullptr;
  110.     int mCurrFrameResourceIndex = 0;
  111.  
  112.     UINT mCbvSrvDescriptorSize = 0;
  113.  
  114.     ComPtr<ID3D12RootSignature> mRootSignature = nullptr;
  115.  
  116.     ComPtr<ID3D12DescriptorHeap> mSrvDescriptorHeap = nullptr;
  117.  
  118.     std::unordered_map<std::string, std::unique_ptr<MeshGeometry>> mGeometries;
  119.     std::unordered_map<std::string, std::unique_ptr<Material>> mMaterials;
  120.     std::unordered_map<std::string, std::unique_ptr<Texture>> mTextures;
  121.     std::unordered_map<std::string, ComPtr<ID3DBlob>> mShaders;
  122.     std::unordered_map<std::string, ComPtr<ID3D12PipelineState>> mPSOs;
  123.  
  124.     std::vector<D3D12_INPUT_ELEMENT_DESC> mInputLayout;
  125.  
  126.     // List of all the render items.
  127.     std::vector<std::unique_ptr<RenderItem>> mAllRitems;
  128.  
  129.     // Render items divided by PSO.
  130.     std::vector<RenderItem*> mRitemLayer[(int)RenderLayer::Count];
  131.  
  132.     RenderItem* mPickedRitem = nullptr;
  133.  
  134.     PassConstants mMainPassCB;
  135.  
  136.     Camera mCamera;
  137.  
  138.     POINT mLastMousePos;
  139. };
  140.  
  141. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE prevInstance,
  142.     PSTR cmdLine, int showCmd)
  143. {
  144.     // Enable run-time memory check for debug builds.
  145. #if defined(DEBUG) | defined(_DEBUG)
  146.     _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  147. #endif
  148.  
  149.     try
  150.     {
  151.         PickingApp theApp(hInstance);
  152.         if(!theApp.Initialize())
  153.             return 0;
  154.  
  155.         return theApp.Run();
  156.     }
  157.     catch(DxException& e)
  158.     {
  159.         MessageBox(nullptr, e.ToString().c_str(), L"HR Failed", MB_OK);
  160.         return 0;
  161.     }
  162. }
  163.  
  164. PickingApp::PickingApp(HINSTANCE hInstance)
  165.     : D3DApp(hInstance)
  166. {
  167. }
  168.  
  169. PickingApp::~PickingApp()
  170. {
  171.     if(md3dDevice != nullptr)
  172.         FlushCommandQueue();
  173. }
  174.  
  175. bool PickingApp::Initialize()
  176. {
  177.     if(!D3DApp::Initialize())
  178.         return false;
  179.  
  180.     // Reset the command list to prep for initialization commands.
  181.     ThrowIfFailed(mCommandList->Reset(mDirectCmdListAlloc.Get(), nullptr));
  182.  
  183.     // Get the increment size of a descriptor in this heap type.  This is hardware specific, 
  184.     // so we have to query this information.
  185.     mCbvSrvDescriptorSize = md3dDevice->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
  186.  
  187.     mCamera.LookAt(
  188.         XMFLOAT3(5.0f, 4.0f, -15.0f),
  189.         XMFLOAT3(0.0f, 1.0f, 0.0f),
  190.         XMFLOAT3(0.0f, 1.0f, 0.0f));
  191.  
  192.     LoadTextures();
  193.     BuildRootSignature();
  194.     BuildDescriptorHeaps();
  195.     BuildShadersAndInputLayout();
  196.     BuildCarGeometry();
  197.     BuildMaterials();
  198.     BuildRenderItems();
  199.     BuildFrameResources();
  200.     BuildPSOs();
  201.  
  202.     // Execute the initialization commands.
  203.     ThrowIfFailed(mCommandList->Close());
  204.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  205.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  206.  
  207.     // Wait until initialization is complete.
  208.     FlushCommandQueue();
  209.  
  210.     return true;
  211. }
  212.  
  213. void PickingApp::OnResize()
  214. {
  215.     D3DApp::OnResize();
  216.  
  217.     mCamera.SetLens(0.25f*MathHelper::Pi, AspectRatio(), 1.0f, 1000.0f);
  218. }
  219.  
  220. void PickingApp::Update(const GameTimer& gt)
  221. {
  222.     OnKeyboardInput(gt);
  223.  
  224.     // Cycle through the circular frame resource array.
  225.     mCurrFrameResourceIndex = (mCurrFrameResourceIndex + 1) % gNumFrameResources;
  226.     mCurrFrameResource = mFrameResources[mCurrFrameResourceIndex].get();
  227.  
  228.     // Has the GPU finished processing the commands of the current frame resource?
  229.     // If not, wait until the GPU has completed commands up to this fence point.
  230.     if(mCurrFrameResource->Fence != 0 && mFence->GetCompletedValue() < mCurrFrameResource->Fence)
  231.     {
  232.         HANDLE eventHandle = CreateEventEx(nullptr, false, false, EVENT_ALL_ACCESS);
  233.         ThrowIfFailed(mFence->SetEventOnCompletion(mCurrFrameResource->Fence, eventHandle));
  234.         WaitForSingleObject(eventHandle, INFINITE);
  235.         CloseHandle(eventHandle);
  236.     }
  237.  
  238.     AnimateMaterials(gt);
  239.     UpdateObjectCBs(gt);
  240.     UpdateMaterialBuffer(gt);
  241.     UpdateMainPassCB(gt);
  242. }
  243.  
  244. void PickingApp::Draw(const GameTimer& gt)
  245. {
  246.     auto cmdListAlloc = mCurrFrameResource->CmdListAlloc;
  247.  
  248.     // Reuse the memory associated with command recording.
  249.     // We can only reset when the associated command lists have finished execution on the GPU.
  250.     ThrowIfFailed(cmdListAlloc->Reset());
  251.  
  252.     // A command list can be reset after it has been added to the command queue via ExecuteCommandList.
  253.     // Reusing the command list reuses memory.
  254.     ThrowIfFailed(mCommandList->Reset(cmdListAlloc.Get(), mPSOs["opaque"].Get()));
  255.  
  256.     mCommandList->RSSetViewports(1, &mScreenViewport);
  257.     mCommandList->RSSetScissorRects(1, &mScissorRect);
  258.  
  259.     // Indicate a state transition on the resource usage.
  260.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  261.         D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));
  262.  
  263.     // Clear the back buffer and depth buffer.
  264.     mCommandList->ClearRenderTargetView(CurrentBackBufferView(), Colors::LightSteelBlue, 0, nullptr);
  265.     mCommandList->ClearDepthStencilView(DepthStencilView(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0f, 0, 0, nullptr);
  266.  
  267.     // Specify the buffers we are going to render to.
  268.     mCommandList->OMSetRenderTargets(1, &CurrentBackBufferView(), true, &DepthStencilView());
  269.  
  270.     ID3D12DescriptorHeap* descriptorHeaps[] = { mSrvDescriptorHeap.Get() };
  271.     mCommandList->SetDescriptorHeaps(_countof(descriptorHeaps), descriptorHeaps);
  272.  
  273.     mCommandList->SetGraphicsRootSignature(mRootSignature.Get());
  274.  
  275.     auto passCB = mCurrFrameResource->PassCB->Resource();
  276.     mCommandList->SetGraphicsRootConstantBufferView(1, passCB->GetGPUVirtualAddress());
  277.  
  278.     // Bind all the materials used in this scene.  For structured buffers, we can bypass the heap and 
  279.     // set as a root descriptor.
  280.     auto matBuffer = mCurrFrameResource->MaterialBuffer->Resource();
  281.     mCommandList->SetGraphicsRootShaderResourceView(2, matBuffer->GetGPUVirtualAddress());
  282.  
  283.     // Bind all the textures used in this scene.  Observe
  284.     // that we only have to specify the first descriptor in the table.  
  285.     // The root signature knows how many descriptors are expected in the table.
  286.     mCommandList->SetGraphicsRootDescriptorTable(3, mSrvDescriptorHeap->GetGPUDescriptorHandleForHeapStart());
  287.  
  288.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Opaque]);
  289.  
  290.     mCommandList->SetPipelineState(mPSOs["highlight"].Get());
  291.     DrawRenderItems(mCommandList.Get(), mRitemLayer[(int)RenderLayer::Highlight]);
  292.  
  293.     // Indicate a state transition on the resource usage.
  294.     mCommandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(CurrentBackBuffer(),
  295.         D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
  296.  
  297.     // Done recording commands.
  298.     ThrowIfFailed(mCommandList->Close());
  299.  
  300.     // Add the command list to the queue for execution.
  301.     ID3D12CommandList* cmdsLists[] = { mCommandList.Get() };
  302.     mCommandQueue->ExecuteCommandLists(_countof(cmdsLists), cmdsLists);
  303.  
  304.     // Swap the back and front buffers
  305.     ThrowIfFailed(mSwapChain->Present(0, 0));
  306.     mCurrBackBuffer = (mCurrBackBuffer + 1) % SwapChainBufferCount;
  307.  
  308.     // Advance the fence value to mark commands up to this fence point.
  309.     mCurrFrameResource->Fence = ++mCurrentFence;
  310.  
  311.     // Add an instruction to the command queue to set a new fence point. 
  312.     // Because we are on the GPU timeline, the new fence point won't be 
  313.     // set until the GPU finishes processing all the commands prior to this Signal().
  314.     mCommandQueue->Signal(mFence.Get(), mCurrentFence);
  315. }
  316.  
  317. void PickingApp::OnMouseDown(WPARAM btnState, int x, int y)
  318. {
  319.     if((btnState & MK_LBUTTON) != 0)
  320.     {
  321.         mLastMousePos.x = x;
  322.         mLastMousePos.y = y;
  323.  
  324.         SetCapture(mhMainWnd);
  325.     }
  326.     else if((btnState & MK_RBUTTON) != 0)
  327.     {
  328.         Pick(x, y);
  329.     }
  330. }
  331.  
  332. void PickingApp::OnMouseUp(WPARAM btnState, int x, int y)
  333. {
  334.     ReleaseCapture();
  335. }
  336.  
  337. void PickingApp::OnMouseMove(WPARAM btnState, int x, int y)
  338. {
  339.     if((btnState & MK_LBUTTON) != 0)
  340.     {
  341.         // Make each pixel correspond to a quarter of a degree.
  342.         float dx = XMConvertToRadians(0.25f*static_cast<float>(x - mLastMousePos.x));
  343.         float dy = XMConvertToRadians(0.25f*static_cast<float>(y - mLastMousePos.y));
  344.  
  345.         mCamera.Pitch(dy);
  346.         mCamera.RotateY(dx);
  347.     }
  348.  
  349.     mLastMousePos.x = x;
  350.     mLastMousePos.y = y;
  351. }
  352.  
  353. void PickingApp::OnKeyboardInput(const GameTimer& gt)
  354. {
  355.     const float dt = gt.DeltaTime();
  356.  
  357.     if(GetAsyncKeyState('W') & 0x8000)
  358.         mCamera.Walk(10.0f*dt);
  359.  
  360.     if(GetAsyncKeyState('S') & 0x8000)
  361.         mCamera.Walk(-10.0f*dt);
  362.  
  363.     if(GetAsyncKeyState('A') & 0x8000)
  364.         mCamera.Strafe(-10.0f*dt);
  365.  
  366.     if(GetAsyncKeyState('D') & 0x8000)
  367.         mCamera.Strafe(10.0f*dt);
  368.  
  369.     mCamera.UpdateViewMatrix();
  370. }
  371.  
  372. void PickingApp::AnimateMaterials(const GameTimer& gt)
  373. {
  374.     
  375. }
  376.  
  377. void PickingApp::UpdateObjectCBs(const GameTimer& gt)
  378. {
  379.     auto currObjectCB = mCurrFrameResource->ObjectCB.get();
  380.     for(auto& e : mAllRitems)
  381.     {
  382.         // Only update the cbuffer data if the constants have changed.  
  383.         // This needs to be tracked per frame resource.
  384.         if(e->NumFramesDirty > 0)
  385.         {
  386.             XMMATRIX world = XMLoadFloat4x4(&e->World);
  387.             XMMATRIX texTransform = XMLoadFloat4x4(&e->TexTransform);
  388.  
  389.             ObjectConstants objConstants;
  390.             XMStoreFloat4x4(&objConstants.World, XMMatrixTranspose(world));
  391.             XMStoreFloat4x4(&objConstants.TexTransform, XMMatrixTranspose(texTransform));
  392.             objConstants.MaterialIndex = e->Mat->MatCBIndex;
  393.  
  394.             currObjectCB->CopyData(e->ObjCBIndex, objConstants);
  395.  
  396.             // Next FrameResource need to be updated too.
  397.             e->NumFramesDirty--;
  398.         }
  399.     }
  400. }
  401.  
  402. void PickingApp::UpdateMaterialBuffer(const GameTimer& gt)
  403. {
  404.     auto currMaterialBuffer = mCurrFrameResource->MaterialBuffer.get();
  405.     for(auto& e : mMaterials)
  406.     {
  407.         // Only update the cbuffer data if the constants have changed.  If the cbuffer
  408.         // data changes, it needs to be updated for each FrameResource.
  409.         Material* mat = e.second.get();
  410.         if(mat->NumFramesDirty > 0)
  411.         {
  412.             XMMATRIX matTransform = XMLoadFloat4x4(&mat->MatTransform);
  413.  
  414.             MaterialData matData;
  415.             matData.DiffuseAlbedo = mat->DiffuseAlbedo;
  416.             matData.FresnelR0 = mat->FresnelR0;
  417.             matData.Roughness = mat->Roughness;
  418.             XMStoreFloat4x4(&matData.MatTransform, XMMatrixTranspose(matTransform));
  419.             matData.DiffuseMapIndex = mat->DiffuseSrvHeapIndex;
  420.  
  421.             currMaterialBuffer->CopyData(mat->MatCBIndex, matData);
  422.  
  423.             // Next FrameResource need to be updated too.
  424.             mat->NumFramesDirty--;
  425.         }
  426.     }
  427. }
  428.  
  429. void PickingApp::UpdateMainPassCB(const GameTimer& gt)
  430. {
  431.     XMMATRIX view = mCamera.GetView();
  432.     XMMATRIX proj = mCamera.GetProj();
  433.  
  434.     XMMATRIX viewProj = XMMatrixMultiply(view, proj);
  435.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(view), view);
  436.     XMMATRIX invProj = XMMatrixInverse(&XMMatrixDeterminant(proj), proj);
  437.     XMMATRIX invViewProj = XMMatrixInverse(&XMMatrixDeterminant(viewProj), viewProj);
  438.  
  439.     XMStoreFloat4x4(&mMainPassCB.View, XMMatrixTranspose(view));
  440.     XMStoreFloat4x4(&mMainPassCB.InvView, XMMatrixTranspose(invView));
  441.     XMStoreFloat4x4(&mMainPassCB.Proj, XMMatrixTranspose(proj));
  442.     XMStoreFloat4x4(&mMainPassCB.InvProj, XMMatrixTranspose(invProj));
  443.     XMStoreFloat4x4(&mMainPassCB.ViewProj, XMMatrixTranspose(viewProj));
  444.     XMStoreFloat4x4(&mMainPassCB.InvViewProj, XMMatrixTranspose(invViewProj));
  445.     mMainPassCB.EyePosW = mCamera.GetPosition3f();
  446.     mMainPassCB.RenderTargetSize = XMFLOAT2((float)mClientWidth, (float)mClientHeight);
  447.     mMainPassCB.InvRenderTargetSize = XMFLOAT2(1.0f / mClientWidth, 1.0f / mClientHeight);
  448.     mMainPassCB.NearZ = 1.0f;
  449.     mMainPassCB.FarZ = 1000.0f;
  450.     mMainPassCB.TotalTime = gt.TotalTime();
  451.     mMainPassCB.DeltaTime = gt.DeltaTime();
  452.     mMainPassCB.AmbientLight = { 0.25f, 0.25f, 0.35f, 1.0f };
  453.     mMainPassCB.Lights[0].Direction = { 0.57735f, -0.57735f, 0.57735f };
  454.     mMainPassCB.Lights[0].Strength = { 0.8f, 0.8f, 0.8f };
  455.     mMainPassCB.Lights[1].Direction = { -0.57735f, -0.57735f, 0.57735f };
  456.     mMainPassCB.Lights[1].Strength = { 0.4f, 0.4f, 0.4f };
  457.     mMainPassCB.Lights[2].Direction = { 0.0f, -0.707f, -0.707f };
  458.     mMainPassCB.Lights[2].Strength = { 0.2f, 0.2f, 0.2f };
  459.  
  460.     auto currPassCB = mCurrFrameResource->PassCB.get();
  461.     currPassCB->CopyData(0, mMainPassCB);
  462. }
  463.  
  464. void PickingApp::LoadTextures()
  465. {
  466.     auto defaultDiffuseTex = std::make_unique<Texture>();
  467.     defaultDiffuseTex->Name = "defaultDiffuseTex";
  468.     defaultDiffuseTex->Filename = L"../../Textures/white1x1.dds";
  469.     ThrowIfFailed(DirectX::CreateDDSTextureFromFile12(md3dDevice.Get(),
  470.         mCommandList.Get(), defaultDiffuseTex->Filename.c_str(),
  471.         defaultDiffuseTex->Resource, defaultDiffuseTex->UploadHeap));
  472.     
  473.     mTextures[defaultDiffuseTex->Name] = std::move(defaultDiffuseTex);
  474. }
  475.  
  476. void PickingApp::BuildRootSignature()
  477. {
  478.     CD3DX12_DESCRIPTOR_RANGE texTable;
  479.     texTable.Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 4, 0, 0);
  480.  
  481.     // Root parameter can be a table, root descriptor or root constants.
  482.     CD3DX12_ROOT_PARAMETER slotRootParameter[4];
  483.  
  484.     // Perfomance TIP: Order from most frequent to least frequent.
  485.     slotRootParameter[0].InitAsConstantBufferView(0);
  486.     slotRootParameter[1].InitAsConstantBufferView(1);
  487.     slotRootParameter[2].InitAsShaderResourceView(0, 1);
  488.     slotRootParameter[3].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
  489.  
  490.  
  491.     auto staticSamplers = GetStaticSamplers();
  492.  
  493.     // A root signature is an array of root parameters.
  494.     CD3DX12_ROOT_SIGNATURE_DESC rootSigDesc(4, slotRootParameter,
  495.         (UINT)staticSamplers.size(), staticSamplers.data(),
  496.         D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);
  497.  
  498.     // create a root signature with a single slot which points to a descriptor range consisting of a single constant buffer
  499.     ComPtr<ID3DBlob> serializedRootSig = nullptr;
  500.     ComPtr<ID3DBlob> errorBlob = nullptr;
  501.     HRESULT hr = D3D12SerializeRootSignature(&rootSigDesc, D3D_ROOT_SIGNATURE_VERSION_1,
  502.         serializedRootSig.GetAddressOf(), errorBlob.GetAddressOf());
  503.  
  504.     if(errorBlob != nullptr)
  505.     {
  506.         ::OutputDebugStringA((char*)errorBlob->GetBufferPointer());
  507.     }
  508.     ThrowIfFailed(hr);
  509.  
  510.     ThrowIfFailed(md3dDevice->CreateRootSignature(
  511.         0,
  512.         serializedRootSig->GetBufferPointer(),
  513.         serializedRootSig->GetBufferSize(),
  514.         IID_PPV_ARGS(mRootSignature.GetAddressOf())));
  515. }
  516.  
  517. void PickingApp::BuildDescriptorHeaps()
  518. {
  519.     //
  520.     // Create the SRV heap.
  521.     //
  522.     D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
  523.     srvHeapDesc.NumDescriptors = 1;
  524.     srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
  525.     srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
  526.     ThrowIfFailed(md3dDevice->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&mSrvDescriptorHeap)));
  527.  
  528.     //
  529.     // Fill out the heap with actual descriptors.
  530.     //
  531.     CD3DX12_CPU_DESCRIPTOR_HANDLE hDescriptor(mSrvDescriptorHeap->GetCPUDescriptorHandleForHeapStart());
  532.  
  533.     auto defaultDiffuseTex = mTextures["defaultDiffuseTex"]->Resource;
  534.  
  535.     D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
  536.     srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
  537.     srvDesc.Format = defaultDiffuseTex->GetDesc().Format;
  538.     srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
  539.     srvDesc.Texture2D.MostDetailedMip = 0;
  540.     srvDesc.Texture2D.MipLevels = defaultDiffuseTex->GetDesc().MipLevels;
  541.     srvDesc.Texture2D.ResourceMinLODClamp = 0.0f;
  542.     md3dDevice->CreateShaderResourceView(defaultDiffuseTex.Get(), &srvDesc, hDescriptor);
  543. }
  544.  
  545. void PickingApp::BuildShadersAndInputLayout()
  546. {
  547.     const D3D_SHADER_MACRO alphaTestDefines[] =
  548.     {
  549.         "ALPHA_TEST", "1",
  550.         NULL, NULL
  551.     };
  552.  
  553.     mShaders["standardVS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "VS", "vs_5_1");
  554.     mShaders["opaquePS"] = d3dUtil::CompileShader(L"Shaders\\Default.hlsl", nullptr, "PS", "ps_5_1");
  555.     
  556.     mInputLayout =
  557.     {
  558.         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  559.         { "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  560.         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 24, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
  561.     };
  562. }
  563.  
  564. void PickingApp::BuildCarGeometry()
  565. {
  566.     std::ifstream fin("Models/car.txt");
  567.  
  568.     if(!fin)
  569.     {
  570.         MessageBox(0, L"Models/car.txt not found.", 0, 0);
  571.         return;
  572.     }
  573.  
  574.     UINT vcount = 0;
  575.     UINT tcount = 0;
  576.     std::string ignore;
  577.  
  578.     fin >> ignore >> vcount;
  579.     fin >> ignore >> tcount;
  580.     fin >> ignore >> ignore >> ignore >> ignore;
  581.  
  582.     XMFLOAT3 vMinf3(+MathHelper::Infinity, +MathHelper::Infinity, +MathHelper::Infinity);
  583.     XMFLOAT3 vMaxf3(-MathHelper::Infinity, -MathHelper::Infinity, -MathHelper::Infinity);
  584.  
  585.     XMVECTOR vMin = XMLoadFloat3(&vMinf3);
  586.     XMVECTOR vMax = XMLoadFloat3(&vMaxf3);
  587.  
  588.     std::vector<Vertex> vertices(vcount);
  589.     for(UINT i = 0; i < vcount; ++i)
  590.     {
  591.         fin >> vertices[i].Pos.x >> vertices[i].Pos.y >> vertices[i].Pos.z;
  592.         fin >> vertices[i].Normal.x >> vertices[i].Normal.y >> vertices[i].Normal.z;
  593.  
  594.         XMVECTOR P = XMLoadFloat3(&vertices[i].Pos);
  595.  
  596.         vertices[i].TexC = { 0.0f, 0.0f };
  597.  
  598.         vMin = XMVectorMin(vMin, P);
  599.         vMax = XMVectorMax(vMax, P);
  600.     }
  601.  
  602.     BoundingBox bounds;
  603.     XMStoreFloat3(&bounds.Center, 0.5f*(vMin + vMax));
  604.     XMStoreFloat3(&bounds.Extents, 0.5f*(vMax - vMin));
  605.  
  606.     fin >> ignore;
  607.     fin >> ignore;
  608.     fin >> ignore;
  609.  
  610.     std::vector<std::int32_t> indices(3 * tcount);
  611.     for(UINT i = 0; i < tcount; ++i)
  612.     {
  613.         fin >> indices[i * 3 + 0] >> indices[i * 3 + 1] >> indices[i * 3 + 2];
  614.     }
  615.  
  616.     fin.close();
  617.  
  618.     //
  619.     // Pack the indices of all the meshes into one index buffer.
  620.     //
  621.  
  622.     const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
  623.  
  624.     const UINT ibByteSize = (UINT)indices.size() * sizeof(std::int32_t);
  625.  
  626.     auto geo = std::make_unique<MeshGeometry>();
  627.     geo->Name = "carGeo";
  628.  
  629.     ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
  630.     CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
  631.  
  632.     ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
  633.     CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
  634.  
  635.     geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  636.         mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
  637.  
  638.     geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
  639.         mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
  640.  
  641.     geo->VertexByteStride = sizeof(Vertex);
  642.     geo->VertexBufferByteSize = vbByteSize;
  643.     geo->IndexFormat = DXGI_FORMAT_R32_UINT;
  644.     geo->IndexBufferByteSize = ibByteSize;
  645.  
  646.     SubmeshGeometry submesh;
  647.     submesh.IndexCount = (UINT)indices.size();
  648.     submesh.StartIndexLocation = 0;
  649.     submesh.BaseVertexLocation = 0;
  650.     submesh.Bounds = bounds;
  651.  
  652.     geo->DrawArgs["car"] = submesh;
  653.  
  654.     mGeometries[geo->Name] = std::move(geo);
  655. }
  656.  
  657. void PickingApp::BuildPSOs()
  658. {
  659.     D3D12_GRAPHICS_PIPELINE_STATE_DESC opaquePsoDesc;
  660.  
  661.     //
  662.     // PSO for opaque objects.
  663.     //
  664.     ZeroMemory(&opaquePsoDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC));
  665.     opaquePsoDesc.InputLayout = { mInputLayout.data(), (UINT)mInputLayout.size() };
  666.     opaquePsoDesc.pRootSignature = mRootSignature.Get();
  667.     opaquePsoDesc.VS = 
  668.     { 
  669.         reinterpret_cast<BYTE*>(mShaders["standardVS"]->GetBufferPointer()), 
  670.         mShaders["standardVS"]->GetBufferSize()
  671.     };
  672.     opaquePsoDesc.PS = 
  673.     { 
  674.         reinterpret_cast<BYTE*>(mShaders["opaquePS"]->GetBufferPointer()),
  675.         mShaders["opaquePS"]->GetBufferSize()
  676.     };
  677.     opaquePsoDesc.RasterizerState = CD3DX12_RASTERIZER_DESC(D3D12_DEFAULT);
  678.     opaquePsoDesc.BlendState = CD3DX12_BLEND_DESC(D3D12_DEFAULT);
  679.     opaquePsoDesc.DepthStencilState = CD3DX12_DEPTH_STENCIL_DESC(D3D12_DEFAULT);
  680.     opaquePsoDesc.SampleMask = UINT_MAX;
  681.     opaquePsoDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
  682.     opaquePsoDesc.NumRenderTargets = 1;
  683.     opaquePsoDesc.RTVFormats[0] = mBackBufferFormat;
  684.     opaquePsoDesc.SampleDesc.Count = m4xMsaaState ? 4 : 1;
  685.     opaquePsoDesc.SampleDesc.Quality = m4xMsaaState ? (m4xMsaaQuality - 1) : 0;
  686.     opaquePsoDesc.DSVFormat = mDepthStencilFormat;
  687.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&opaquePsoDesc, IID_PPV_ARGS(&mPSOs["opaque"])));
  688.  
  689.     //
  690.     // PSO for highlight objects
  691.     //
  692.  
  693.     D3D12_GRAPHICS_PIPELINE_STATE_DESC highlightPsoDesc = opaquePsoDesc;
  694.  
  695.     // Change the depth test from < to <= so that if we draw the same triangle twice, it will
  696.     // still pass the depth test.  This is needed because we redraw the picked triangle with a
  697.     // different material to highlight it.  If we do not use <=, the triangle will fail the 
  698.     // depth test the 2nd time we try and draw it.
  699.     highlightPsoDesc.DepthStencilState.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
  700.  
  701.     // Standard transparency blending.
  702.     D3D12_RENDER_TARGET_BLEND_DESC transparencyBlendDesc;
  703.     transparencyBlendDesc.BlendEnable = true;
  704.     transparencyBlendDesc.LogicOpEnable = false;
  705.     transparencyBlendDesc.SrcBlend = D3D12_BLEND_SRC_ALPHA;
  706.     transparencyBlendDesc.DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
  707.     transparencyBlendDesc.BlendOp = D3D12_BLEND_OP_ADD;
  708.     transparencyBlendDesc.SrcBlendAlpha = D3D12_BLEND_ONE;
  709.     transparencyBlendDesc.DestBlendAlpha = D3D12_BLEND_ZERO;
  710.     transparencyBlendDesc.BlendOpAlpha = D3D12_BLEND_OP_ADD;
  711.     transparencyBlendDesc.LogicOp = D3D12_LOGIC_OP_NOOP;
  712.     transparencyBlendDesc.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;
  713.  
  714.     highlightPsoDesc.BlendState.RenderTarget[0] = transparencyBlendDesc;
  715.     ThrowIfFailed(md3dDevice->CreateGraphicsPipelineState(&highlightPsoDesc, IID_PPV_ARGS(&mPSOs["highlight"])));
  716. }
  717.  
  718. void PickingApp::BuildFrameResources()
  719. {
  720.     for(int i = 0; i < gNumFrameResources; ++i)
  721.     {
  722.         mFrameResources.push_back(std::make_unique<FrameResource>(md3dDevice.Get(),
  723.             1, (UINT)mAllRitems.size(), (UINT)mMaterials.size()));
  724.     }
  725. }
  726.  
  727. void PickingApp::BuildMaterials()
  728. {
  729.     auto gray0 = std::make_unique<Material>();
  730.     gray0->Name = "gray0";
  731.     gray0->MatCBIndex = 0;
  732.     gray0->DiffuseSrvHeapIndex = 0;
  733.     gray0->DiffuseAlbedo = XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f);
  734.     gray0->FresnelR0 = XMFLOAT3(0.04f, 0.04f, 0.04f);
  735.     gray0->Roughness = 0.0f;
  736.  
  737.     auto highlight0 = std::make_unique<Material>();
  738.     highlight0->Name = "highlight0";
  739.     highlight0->MatCBIndex = 1;
  740.     highlight0->DiffuseSrvHeapIndex = 0;
  741.     highlight0->DiffuseAlbedo = XMFLOAT4(1.0f, 1.0f, 0.0f, 0.6f);
  742.     highlight0->FresnelR0 = XMFLOAT3(0.06f, 0.06f, 0.06f);
  743.     highlight0->Roughness = 0.0f;
  744.  
  745.     
  746.     mMaterials["gray0"] = std::move(gray0);
  747.     mMaterials["highlight0"] = std::move(highlight0);
  748. }
  749.  
  750. void PickingApp::BuildRenderItems()
  751. {
  752.     auto carRitem = std::make_unique<RenderItem>();
  753.     XMStoreFloat4x4(&carRitem->World, XMMatrixScaling(1.0f, 1.0f, 1.0f)*XMMatrixTranslation(0.0f, 1.0f, 0.0f));
  754.     XMStoreFloat4x4(&carRitem->TexTransform, XMMatrixScaling(1.0f, 1.0f, 1.0f));
  755.     carRitem->ObjCBIndex = 0;
  756.     carRitem->Mat = mMaterials["gray0"].get();
  757.     carRitem->Geo = mGeometries["carGeo"].get();
  758.     carRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  759.     carRitem->Bounds = carRitem->Geo->DrawArgs["car"].Bounds;
  760.     carRitem->IndexCount = carRitem->Geo->DrawArgs["car"].IndexCount;
  761.     carRitem->StartIndexLocation = carRitem->Geo->DrawArgs["car"].StartIndexLocation;
  762.     carRitem->BaseVertexLocation = carRitem->Geo->DrawArgs["car"].BaseVertexLocation;
  763.     mRitemLayer[(int)RenderLayer::Opaque].push_back(carRitem.get());
  764.  
  765.     auto pickedRitem = std::make_unique<RenderItem>();
  766.     pickedRitem->World = MathHelper::Identity4x4();
  767.     pickedRitem->TexTransform = MathHelper::Identity4x4();
  768.     pickedRitem->ObjCBIndex = 1;
  769.     pickedRitem->Mat = mMaterials["highlight0"].get();
  770.     pickedRitem->Geo = mGeometries["carGeo"].get();
  771.     pickedRitem->PrimitiveType = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
  772.  
  773.     // Picked triangle is not visible until one is picked.
  774.     pickedRitem->Visible = false;
  775.  
  776.     // DrawCall parameters are filled out when a triangle is picked.
  777.     pickedRitem->IndexCount = 0;
  778.     pickedRitem->StartIndexLocation = 0;
  779.     pickedRitem->BaseVertexLocation = 0;
  780.     mPickedRitem = pickedRitem.get();
  781.     mRitemLayer[(int)RenderLayer::Highlight].push_back(pickedRitem.get());
  782.  
  783.  
  784.     mAllRitems.push_back(std::move(carRitem));
  785.     mAllRitems.push_back(std::move(pickedRitem));
  786. }
  787.  
  788. void PickingApp::DrawRenderItems(ID3D12GraphicsCommandList* cmdList, const std::vector<RenderItem*>& ritems)
  789. {
  790.     UINT objCBByteSize = d3dUtil::CalcConstantBufferByteSize(sizeof(ObjectConstants));
  791.  
  792.     auto objectCB = mCurrFrameResource->ObjectCB->Resource();
  793.  
  794.     // For each render item...
  795.     for(size_t i = 0; i < ritems.size(); ++i)
  796.     {
  797.         auto ri = ritems[i];
  798.  
  799.         if(ri->Visible == false)
  800.             continue;
  801.  
  802.         cmdList->IASetVertexBuffers(0, 1, &ri->Geo->VertexBufferView());
  803.         cmdList->IASetIndexBuffer(&ri->Geo->IndexBufferView());
  804.         cmdList->IASetPrimitiveTopology(ri->PrimitiveType);
  805.  
  806.         D3D12_GPU_VIRTUAL_ADDRESS objCBAddress = objectCB->GetGPUVirtualAddress() + ri->ObjCBIndex*objCBByteSize;
  807.  
  808.         cmdList->SetGraphicsRootConstantBufferView(0, objCBAddress);
  809.  
  810.         cmdList->DrawIndexedInstanced(ri->IndexCount, 1, ri->StartIndexLocation, ri->BaseVertexLocation, 0);
  811.     }
  812. }
  813.  
  814. std::array<const CD3DX12_STATIC_SAMPLER_DESC, 6> PickingApp::GetStaticSamplers()
  815. {
  816.     // Applications usually only need a handful of samplers.  So just define them all up front
  817.     // and keep them available as part of the root signature.  
  818.  
  819.     const CD3DX12_STATIC_SAMPLER_DESC pointWrap(
  820.         0, // shaderRegister
  821.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  822.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  823.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  824.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  825.  
  826.     const CD3DX12_STATIC_SAMPLER_DESC pointClamp(
  827.         1, // shaderRegister
  828.         D3D12_FILTER_MIN_MAG_MIP_POINT, // filter
  829.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  830.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  831.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  832.  
  833.     const CD3DX12_STATIC_SAMPLER_DESC linearWrap(
  834.         2, // shaderRegister
  835.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  836.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  837.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  838.         D3D12_TEXTURE_ADDRESS_MODE_WRAP); // addressW
  839.  
  840.     const CD3DX12_STATIC_SAMPLER_DESC linearClamp(
  841.         3, // shaderRegister
  842.         D3D12_FILTER_MIN_MAG_MIP_LINEAR, // filter
  843.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  844.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  845.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP); // addressW
  846.  
  847.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicWrap(
  848.         4, // shaderRegister
  849.         D3D12_FILTER_ANISOTROPIC, // filter
  850.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressU
  851.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressV
  852.         D3D12_TEXTURE_ADDRESS_MODE_WRAP,  // addressW
  853.         0.0f,                             // mipLODBias
  854.         8);                               // maxAnisotropy
  855.  
  856.     const CD3DX12_STATIC_SAMPLER_DESC anisotropicClamp(
  857.         5, // shaderRegister
  858.         D3D12_FILTER_ANISOTROPIC, // filter
  859.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressU
  860.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressV
  861.         D3D12_TEXTURE_ADDRESS_MODE_CLAMP,  // addressW
  862.         0.0f,                              // mipLODBias
  863.         8);                                // maxAnisotropy
  864.  
  865.     return { 
  866.         pointWrap, pointClamp,
  867.         linearWrap, linearClamp, 
  868.         anisotropicWrap, anisotropicClamp };
  869. }
  870.  
  871. void PickingApp::Pick(int sx, int sy)
  872. {
  873.     XMFLOAT4X4 P = mCamera.GetProj4x4f();
  874.  
  875.     // Compute picking ray in view space.
  876.     float vx = (+2.0f*sx / mClientWidth - 1.0f) / P(0, 0);
  877.     float vy = (-2.0f*sy / mClientHeight + 1.0f) / P(1, 1);
  878.  
  879.     // Ray definition in view space.
  880.     XMVECTOR rayOrigin = XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f);
  881.     XMVECTOR rayDir = XMVectorSet(vx, vy, 1.0f, 0.0f);
  882.     
  883.     XMMATRIX V = mCamera.GetView();
  884.     XMMATRIX invView = XMMatrixInverse(&XMMatrixDeterminant(V), V);
  885.  
  886.     // Assume nothing is picked to start, so the picked render-item is invisible.
  887.     mPickedRitem->Visible = false;
  888.  
  889.     // Check if we picked an opaque render item.  A real app might keep a separate "picking list"
  890.     // of objects that can be selected.   
  891.     for(auto ri : mRitemLayer[(int)RenderLayer::Opaque])
  892.     {
  893.         auto geo = ri->Geo;
  894.  
  895.         // Skip invisible render-items.
  896.         if(ri->Visible == false)
  897.             continue;
  898.  
  899.         XMMATRIX W = XMLoadFloat4x4(&ri->World);
  900.         XMMATRIX invWorld = XMMatrixInverse(&XMMatrixDeterminant(W), W);
  901.  
  902.         // Tranform ray to vi space of Mesh.
  903.         XMMATRIX toLocal = XMMatrixMultiply(invView, invWorld);
  904.  
  905.         rayOrigin = XMVector3TransformCoord(rayOrigin, toLocal);
  906.         rayDir = XMVector3TransformNormal(rayDir, toLocal);
  907.  
  908.         // Make the ray direction unit length for the intersection tests.
  909.         rayDir = XMVector3Normalize(rayDir);
  910.  
  911.         // If we hit the bounding box of the Mesh, then we might have picked a Mesh triangle,
  912.         // so do the ray/triangle tests.
  913.         //
  914.         // If we did not hit the bounding box, then it is impossible that we hit 
  915.         // the Mesh, so do not waste effort doing ray/triangle tests.
  916.         float tmin = 0.0f;
  917.         if(ri->Bounds.Intersects(rayOrigin, rayDir, tmin))
  918.         {
  919.             // NOTE: For the demo, we know what to cast the vertex/index data to.  If we were mixing
  920.             // formats, some metadata would be needed to figure out what to cast it to.
  921.             auto vertices = (Vertex*)geo->VertexBufferCPU->GetBufferPointer();
  922.             auto indices = (std::uint32_t*)geo->IndexBufferCPU->GetBufferPointer();
  923.             UINT triCount = ri->IndexCount / 3;
  924.  
  925.             // Find the nearest ray/triangle intersection.
  926.             tmin = MathHelper::Infinity;
  927.             for(UINT i = 0; i < triCount; ++i)
  928.             {
  929.                 // Indices for this triangle.
  930.                 UINT i0 = indices[i * 3 + 0];
  931.                 UINT i1 = indices[i * 3 + 1];
  932.                 UINT i2 = indices[i * 3 + 2];
  933.  
  934.                 // Vertices for this triangle.
  935.                 XMVECTOR v0 = XMLoadFloat3(&vertices[i0].Pos);
  936.                 XMVECTOR v1 = XMLoadFloat3(&vertices[i1].Pos);
  937.                 XMVECTOR v2 = XMLoadFloat3(&vertices[i2].Pos);
  938.  
  939.                 // We have to iterate over all the triangles in order to find the nearest intersection.
  940.                 float t = 0.0f;
  941.                 if(TriangleTests::Intersects(rayOrigin, rayDir, v0, v1, v2, t))
  942.                 {
  943.                     if(t < tmin)
  944.                     {
  945.                         // This is the new nearest picked triangle.
  946.                         tmin = t;
  947.                         UINT pickedTriangle = i;
  948.  
  949.                         mPickedRitem->Visible = true;
  950.                         mPickedRitem->IndexCount = 3;
  951.                         mPickedRitem->BaseVertexLocation = 0;
  952.  
  953.                         // Picked render item needs same world matrix as object picked.
  954.                         mPickedRitem->World = ri->World;
  955.                         mPickedRitem->NumFramesDirty = gNumFrameResources;
  956.  
  957.                         // Offset to the picked triangle in the mesh index buffer.
  958.                         mPickedRitem->StartIndexLocation = 3 * pickedTriangle;
  959.                     }
  960.                 }
  961.             }
  962.         }
  963.     }
  964. }